perm filename POINTY.DOC[PNT,HE] blob
sn#562756 filedate 1981-02-12 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00018 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 PURPOSE OF THIS FILE
C00004 00003 IMPLEMENTATION COMMENTS
C00008 00004 THE SCANNER
C00015 00005 THE PARSER
C00022 00006 SYMBOL TABLE ORGANIZATION
C00031 00007 INITIALIZATIONS
C00035 00008 FILE TABLE ORGANIZATION
C00040 00009 DISPLAY
C00045 00010 HOW "KILL" IS IMPLEMENTED
C00050 00011 DEFAULT PARTS
C00053 00012 HOW "CONSTRUCT" IS IMPLEMENTED
C00056 00013 HOW TO HANDLE THE ROTATION MATRIX
C00064 00014 THE EXPRESSION EVALUATOR
C00068 00015 SOURCE FILE PROTOCOL
C00071 00016 DOCUMENTATION OF THE DEBUGGING FACILITIES IN POINTY
C00083 00017 IMPLEMENTATION
C00090 00018 POINTY RUNTIME
C00091 ENDMK
C⊗;
PURPOSE OF THIS FILE
This file is a legacy of Maria Gini and Pina Gini left behind
to explain in an informal way the control structure of the final POINTY
system, and meant to help anybody who plans to modify/use POINTY.
The file was originally put together by Maria (whose programmer name is MLG)
whom we should verbally thank each time we use this file instead of
having to chase through half a dozen files trying to figure where is
what.
Shahid 1-5-78. [MSM]
This file is updated to reflect the current state of implementation
as far as possible.
IMPLEMENTATION COMMENTS
Some comments about some implementation choices are in next pages.
The program is in the file POINTY.SAI[PNT,HE].
It requires some source files and load modules
conditional source file load module
flag
MAINPR.SAI[PNT,HE]
MACROS.SAI[PNT,HE]
RECORD.DEF[PNT,HE]
PARSER.HDR[PNT,HE] PARSER[PNT,HE]
OPERAT.HDR[PNT,HE] OPERAT[PNT,HE]
OUTPUT.HDR[PNT,HE] OUTPUT[PNT,HE]
ARMINT.SAI[PNT,MSM] TLKF5a[PNT,HE]
#KILL KILLER.HDR[PNT,HE] KILLER[PNT,HE]
#HELP HELP.HDR[PNT,HE] HELP[PNT,HE]
#ARROW ARROW[PNT,HE]
#DISPL DISPLY[PNT,HE]
#OUTPT INPOUT[PNT,HE]
#MOVE ( TLKF3a[PNT,HE]
( MOVARM[PNT,HE]
( BEJCZY[PNT,HE]
( ARMSOL[PNT,HE]
file purpose
HELP used by HELP.SAI to read the explanations about the syntax.
POINTY.SAI outermost file with specified compilation flags for a complete
version of POINTY.
MACROS.SAI useful macro definitions
RECORD.DEF external declarations for the record classes, the
symbol table and the pointers to the predefined variables
PARSER.SAI basic parsing procedures
OPERAT.SAI basic arithmetic operations
EXPR.SAI procedures for parsing and calling the arithmetic expressions
OUTPUT.SAI procedures to construct the string with the decoded
values of the different variables for printing
DISPLY.SAI display procedures
INPOUT.SAI for file output (read is in MAINPR)
KILLER.SAI procedures required by KILL instruction
HELP.SAI procedures for the complete error explanations and syntax
messages
ARROW.SAI contains procedure for drawing arrow on the display.
**********************
The previous working version of POINTY is POINTY.OLD[PNT,HE].
The dump file is OLD.DMP[PNT,HE]. This was the state of the world
as of end of December, 1977, and meant as backup in case there
are some bugs in the new version.
THE SCANNER
The current line is saved in $CLNE. The part of line remaining to be scanned
is in $CLINR. Initially $CLINR=$CLNE. $CLNE may at any time contain exactly,
or more or less than one instruction. The actual process of getting
the next line is done in procedure NEWLINE, which remembers which is the
current input device - the teletype, disk or a tempory buffer from the
teletype which is used to type correction information and responses to prompts.
GTOKEN obtains the next token and returns certain information in the global
variables TOKEN, TOKENINDEX, TOKENPTR, RES_CLASS depending on the nature of
the token.
Anything within curly brackets (and the brackets themselves) is totally
ignored by GTOKEN, so that comments may be enclosed within curly brackets.
Since this is handled by GTOKEN, the parser never sees curly brackets.
Different break tables are used by the parser and the scanner.
The general table used in the main loop to separate one instruction from
the others is $SCNTAB. Its specifications are expressed in SAIL by
SETBREAK ($SCNTAB←GETBREAK,";?{",CR&LF&FF&TV,"INAK");
THE SCANNER
The procedure GTOKEN reads the next token in the string $CLNR and
returns it in TOKEN. The syntactic type of TOKEN is in #TOKEN.
It is ID_TYPE for identifiers,
INT_TYPE for integer numbers,
REAL_TYPE for real numbers,
OPERATOR_TYPE for punctuation marks, operators..
UNDECLARED_TYPE for undeclared variables,
RESERVED_TYPE for reserved words.
GTOKEN uses different break tables
BTABLE←".,;[]()+-*/←↑↓→?α$"&LF&CR&TAB&FF&SP;
SETBREAK ($RETAB ←GETBREAK,BTABLE,NULL,"INR");
is used to read the token, retaining the break character
SETBREAK ($SKTAB ←GETBREAK,BTABLE,NULL,"INS");
is used to read the token after using $RETAB, just to skip the break
character left before in the string
SETBREAK ($SPCTAB←GETBREAK,TAB&SP,NULL, "XNR");
is used to skip the blanks before the token
SETBREAK ($ALFTAB←GETBREAK,NULL,NULL,"XRN");
is used to read one character from the string, usually to check if it's a
number or not
SETBREAK ($NUMTAB←GETBREAK,"@+-0123456789",NULL,"XNR"); ! as table 10;
is used while reading a number to detect the first non-number character
GTOKEN is to skips blanks and tabs, and reads the token
retaining the break character. The action is then dictated by the token and
the break. If the token is null there are two cases: can be a number (as
.12@3) or simply a punctuation mark(as . or ,) or the end of the string in
one instruction requiring more typing(instruction typed in different
lines). So these cases are identified taking a look at the break
character and deciding either to wait for more input (break=<cr> and flag
indicating the instruction is not terminated), or to return a punctuation
mark or again to continue reading a number. If the break character is a .
two cases are possible, because it can be part of a floating number or can
be only a punctuation mark.
If the token read at the beginning is not null two different cases are
possible: the break is a . or is a different character so the token is an
identifier.
In the first case (break .) the string is scanned to see if the token is
composed only by numbers (in that case is a floating number and other more
numbers can be present after .) or if the token is simply an identifier
followed by a .
If after this process the token results to be an identifier there is
another check to be done, because it can be an integer number. So the
token is scanned again, looking at the first character to see if it's a
number. In that case the other characters are checked to define the
correct type of the token.
Other break tables are used for different purposes.
* $DSTTAB is used by COPY/MERGE instructions to find if there is an
underscore in the name of the frames.
* $ERRTAB is used by the recover procedure to check if the new name typed
is an identifier. If a break character is found the recover will proceed
asking to type again a correct isdentifier. During the scanning spaces and
<cr>'s are eliminated.
* $BSKTAB is used for the display to compact the output, by erasing the
spaces.
THE PARSER
Parsing is done by the procedure PARSE.
PARSE checks the first token of the instruction to
detect what kind of instruction it is. In fact the instructions begin
with a reserved word, unless they are assignment instructions (or the
reserved word is mispelled!!), and calls the relevant procedure to
parse the rest of the statement.
SYMBOL TABLE ORGANIZATION
The symbol table is constituted by an array $YMTAB, whose elements are
rptr's to records of class SYMBOL.
* the number of positions in $YMTAB is #LMT+1, with #LMT=499.
The symbol table is then divided in parts, one for each type of variables.
* the number of the types is #NTYPE, with #NTYPE=#MAX-#MIN+1
where #MIN = 1 and #MAX = 5.
They correspond to SCALAR, VECTOR, ROT, FRAME, TRANS, MACRO, FUNCTION
* the number of positions for each type is #LTYPE. It's given by
#LTYPE= 70.
* the type SCALAR is in the first part of $YMTAB (#SC=1=#MIN), the
type VECTOR in the second (#VT=2), the type ROT in the third (#RT=3),
the type TRANS in the fourth (#TR=4) and the type FRAME in the fifth
(#FR=5).
* #SC, #VT, #RT, #FR, #TR, #MC and #FN are used to enter in the
appropriate part of $YMTAB.
The records of class SYMBOL have several fields
pname, is the name of the symbol (string),
object, is the rptr to the record of the appropriate class.
nuses, the number of different outside variables used by this symbol
currently appropriate for functions
nusedby, the number of different functions that use this symbol
valid, a boolean flag telling whether this is a valid symbol in
in the symbol table or deleted from the symbol table
arrays usedby[1:nusedby] which is an array of the expression record
pointers to symbols which use this symbol
array uses[1:nuses} which is an array of expression record pointers
to symbols which are used by this symbol.
The integer array $ENTRY is used to keep track of the number of elements
inserted in $YMTAB.
* the number of positions in $ENTRY is #NTYPE
* each position in $ENTRY corresponds to one type of variables
* each position contains the entry in $YMTAB of the first position
free for the corresponding type.
* the range of values for the i-element of $ENTRY (orresponding to all
the entries in $YMTAB for the class i) is given by
#LTYPE*(i-#MIN)≤ $ENTRY[i] ≤ (#LTYPE*i)-#MIN
* when entries from the symbol table are deleted, $ENTRY value is
reduced by 1, and the last symbol of this type in the symbol table
is shifted up to occupy the vacant spot in $YMTAB. This means that
space can be created in the symbol table by deleting some previously
declared symbols.
The different types of variables are stored on different types of records.
* SCALAR
scalar:value contains the real value of the scalar
* VECTOR
vector:xc contains the real value of the component along x-axis
vector:yc contains the real value of the component along y-axis
vector:zc contains the real value of the component along z-axis
* ROT
rot:xf is a real array[1:5,1:4], as in FRAME
* FRAME
frame:pname contains the pname of the frame (string)
frame:dad contains the pointer to its dad in the tree
frame:son contains the pointer to its last son
frame:ebro contains the pointer to its elder brother
frame:ybro contains the pointer to its younger brother
frame:howlinked contains the kind of affixment(#RGDLK,#NRGLK,#INDLK)
frame:xf is a real arry containing
xf[1:3,1:3]=rotation matrix,
xf[1:3,4]=translation vector,
xf[4,1:3]=0,
xf[4,4]=1,
xf[5,1:3]=rotation angles (euler angles)
xf[5,4]>0 if angles are valid;
* TRANS
trans:xf is a real array [1:5,1:4], as in FRAME
SYMTAB[0:lmt] symbol scalar
______ _______________ _________
| | | | | | |
| -|---------→|pname|object-|--------→| value |
|____| |_____|_______| |_______|
| |
| -|-----→..
|____|
| |
| .. | vector
|____| _______________ __________
| | | | | | | | |
| -|---------→|pname|object-|--------→|xc|yc|zc|
|____| |_____|_______| |__|__|__|
| |
| -|-----→..
|____|
| |
| .. | rot
|____| _______________ ____________
| | | | | | |
| -|---------→|pname|object-|--------→|xf(array) |
|____| |_____|_______| |__________|
| |
| -|-----→...
|____|
| |
| .. | frame
|____| _______________ ______________________________________
| | | | | | | | | | | | |
| -|---------→|pname|object-|--------→|pname|xf|dad|son|ebro|ybro|howlinked|
|____| |_____|_______| |_____|__|_|_|_|_|_|__|_|__|_________|
| | ↓ ↓ ↓ ↓
| -|-----→.. frame
|____|
| |
| .. | trans
|____| _______________ ____________
| | | | | | |
| -|---------→|pname|object-|--------→|xf(array) |
|____| |_____|_______| |__________|
| |
| -|-----→...
|____|
| |
| .. |
|____|
There are many predeclared symbols. Their pointers and values are described
in the session about initialization.
Some other pointers are defined, to keep track of some important information,
or to define some variable internally used, as
rptr(frame)
F_ARM, used to remember what arm is holding the pointer,
F_FID used to store the rptr to the FIDUCIAL point (when defined)
rptr(trans)
ARRAY T_CSTR[1:3] used to store the frames defined by CONSTRUCT
without arguments
INITIALIZATIONS
PROCEDURES REQUIRING TO BE INITIALIZED
INIBRK
initializes the break tables
initializes the string $BLANK
sets the number of decimal characters for real numbers to 3.
INISYM
initializes the symbol table.
VARIABLES REQUIRING TO BE INITIALIZED
$ALFL←"DECLAR.AL"
default name for input/output file
$EPS = 0.001
is a value used for tests while using trigonometric functions
$READ←FALSE
used by readcode: true while reading
PREDECLARED POINTY VARIABLES
the first element is the pname (printname) of the variable
the second is the record_pointer to the record of class SYMBOL
the third is the record_pointer to the record of the particular
class (SCALAR,VECTOR,ROT,TRANS,FRAME). These names begin with the
initial of the class name and an underscore
the fourth is the value. Values for rot, frame and trans are expressed
by six elements (w,ph,th,x,y,z) corresponding to
(rot(zhat,th)*rot(yhat,ph)*rot(zhat,w),vector(x,y,z))
pname(string) rptr(symbol) rptr(scalar) value
BHAND HANDB S_BHAND
YHAND HANDY S_YHAND
DEG DEG 1
DEGREE DEGREE 1
DEGREES DEGRES 1
INCH INCH 1
INCHES INCHES 1
rptr(vector)
XHAT XHAT V_XHAT (1,0,0)
YHAT YHAT V_YHAT (0,1,0)
ZHAT ZHAT V_ZHAT (0,0,1)
NILVECT NILVECT V_NILVECT (0,0,0)
rptr(rot)
NILROTN NILROTN R_NILROTN (0,0,0) euler angles
rptr(frame)
STATION WORLD F_WRLD (0,0,0,0,0,0)
BPARK BPARK F_BPARK (0,180,0,
43.53125,56.855,9.95875)
YPARK YPARK F_YPARK (0,180,0,40,14,9)
BARM BARM F_BARM
YARM YARM F_YARM (0,0,0,0,0,0)
BGRASP BGRASP F_BGRASP (-180,180,0,0,0,0)
affixed to BARM
POINTER POINTER F_POINTER (-.417,13.2,-5.173,
.0121,.119,3.75)
affixed to BARM
rptr(trans)
NILTRANS NILTRANS T_NILTRANS (0,0,0,0,0,0)
******* important notice
If other predefined variables are inserted the values in the array SAVE of
the procedure RESET in MAINPR.SAI have to be accordingly modified;
FILE TABLE ORGANIZATION
POINTY allows to write on different files, to save or to close them. The
names of the files used, and their status are mantained in a file table,
with an index to know the number of used files. That table is constituted
by two matrices. The information about one file can be found in those two
matrices on the same row.
* $NAMEFL is a string array [1:10], used for the file names
* $CHNFL is an integer array [1:10,0:1], containing in the first
column the status open(0)/close(1) of the file and in the second
column the number of the channel associated.
* $TOTFL is an integer, whose value is the total number of files
used.
$NAMEFL $CHNFL
______________ __________________________
|name of file| |open/close | channel # |
|(string) | | 0 1 | |
|____________| |___________|____________|
| | | | |
| | | | |
The last file used for output is the default name for output instruction.
We'll call this "current file".
* $ALFL, is a string containing the name of the current file
(initialized with DECLAR.AL). When the current file is closed the
name of a previously used open file is taken as default, or, if
there are'nt any DECLAR.AL is taken. The current file is indicated
on the display by a * before the file name.
* $ALCH is the channel number of the current file.
The output of TTY can be saved in a file. The name of this file is given
at the start of the session, and can be changed only by the instruction
CLOSE_FILES. In the case the TTY output has to be recorded same variables
are used
* $OUT, is used as a flag to know if the output has to be saved
* $TTYFL is the name of the file
* $TTYCH is the channel number.
The input in TTY is converted in upper cases, so lower or upper cases can
be used in any combination. There are problems only while recovering,
because the characters typed into the line editor are not converted.
For READ instruction the global variables used are
* $READ, used as flag to know if the instruction being executed is
a READ instruction. The flag is required to continue with the
reading in the case the file contains an error, since each error
causes a goto to the main loop
* $INPCH is the number of the channel associated with the input
file. It'used to remember the channel number after an error, and
it's also used by SAVE instruction, when the saved file is read
and copied.
DISPLAY
Some of the procedures for the display are in DISPLY.SAI[1,MLG].
The global variables used in that file are prefixed by ∂.
That file requires
source file load_module
DPYSUB.HDR[SUB,SYS] DPYSUB.SAI[SUB,SYS] DPYSUB[SUB,SYS]
The procedure INIDPY initializes the display, assigning the appropriate
values to the variables defining margin positions.
∂DLMAR ∂SCFR ∂DRMAR
↓ ↓ ↓
_________________________________
∂DTMAR→ | | |
| | |
| FRAME TREE | SC |
| TRANS |-------| ← ∂SCDF
∂TRFL→ |_______________________|_______|
| | | |
| FILE | ROT | VT |
|__________|__________|_________|
∂TPMAR→
↑ ↑
∂FLRT ∂RTVT
∂DBMAR →
The internal/external variables are
$ARROW position of the arrow
external integer
$BLANK string of blanks
external string
$BRCHR break character
external integer
$BSKTAB break table used to get ride of blanks
external integer
$DPYTAB breaktable used to split the string
external integer in different lines)
$EPS
external real
$NCHAR number of characters for frame space
internal integer (=∂wfr/∂chwid)
The external procedure used is
EULERO(REAL ARRAY XF;REFERENCE REAL W,PH,TH);
The global variables of DISPLY.SAI are
∂BUF buffer for the display
integer array [1:1000]
∂CHWID width of a character(=15 on DD,12 on III)
∂CHIGH height of a line (=20)
∂DBMAR bottom margin of the display (=-510 on DD,
-450 on III)
∂DLMAR left margin (=-625 on DD,-510 on III)
∂DRMAR right margin (=580 on DD, 510 on III)
∂DTMAR top margin (=450)
∂DWNLNS number of lines for lower part of display
(=12)
∂FLRT margin between files and rot's
(=-330 on DD,-215 on III)
∂RTVT margin between rot's and vectors
(=175 on DD, 147 on III)
∂SCDF margin between defaults and scalars(=-10)
∂SCFR margin between frames and scalars
(=400 ON DD,330 ON III)
∂SIZE size of the characters (=2)
∂TPMAR typing space top margin (=-318 on DD,
-270 on III)
∂TRFL trans's bottom margin (=-70)
∂UPLNS number of lines in upper part of display
(= 26)
∂WFR width of space for frame tree
(=1015 on DD,830 on III)
∂WRTVT width of space for vectors and rot's
(=495 on DD,352 on III)
∂WSC width of space for scalars (=170)
The procedure ARROW draws an arrow on the screen
. 80 . 20 .
c3y ..................3.....................
. |\ . 10
c12y 1 ________________2| \ .................
| . \ .
c4y | . \4 20
| . /.
|__________________ /................
c67y 7. 6| / . 10
c5y ..................|/....................
. 5 .
. . .
c17x c2356x c4x ;
It's possible to move by one line the array with the instruction ↑ , ↓ than can
be preceded by any integer number.
HOW "KILL" IS IMPLEMENTED
The kill instruction allows to delete the last instruction and its side
effects. Each time an instruction is parsed the kill is initialized by
INIKIL, which sets to null_record the record pointer to the record (or
list of records) used to save the information about the variables being
modified. That record pointer is KILL.
With that implementation would be very easy to save more than one
instruction, allowing so to delete more than the last one. It's enough to
save not only one record pointer (for the last instruction), but more
record pointers (in a circular list)and for each instruction delete the
oldest and insert the new one.
The records used are of class SAVED, where
saved:addr is the address (row number) in $YMTAB of the symbol
modified.
saved:type is the type of that symbol (#sc,#vt,#rt,#fr,#tr) or
is a special type #nw, for new symbols, or #nwfr, for
new frames. That choice ease the handling of the record.
saved:symbol is the record pointer to the record of class symbol.
If the symbol is a new defined one is null_record.
saved:object is the record pointer to the record of one type (#sc,
#vt,#rt,#fr,#tr) if the record is created in the same
instruction (so the type is #nw or #nwfr) or to the record
used to copy the value of the modified variable.
saved:dad is the record pointer to the dad of the frame (used only
when tree modifications are involved).
saved:link is the kind of affixment (same as before).
saved:next is the pointer to next record of the same type. All
the records used to save information about one POINTY
instruction are connected by this link, so it's possible
to follow that chain to restore the previous situation.
How to save the information
There are two main procedures to save the status of a variable
SAVNEW, saves the status of a variable being defined in the instruction
itself. In that case saved:addr is taken from $ENTRY, and saved:object
is the rptr to the symbol. So if the instruction is killed is enough
to delete the symbol from $YMTAB.
SAVOLD, saves the status of a variable previously defined which
is modified in the instruction. A variable is used to remember the
address in $YMTAB of teh last checked symbol, $ROW. Its value is
inserted in saved:addr. Then a new record is constructed
How to recover
To know what was the last instruction a variable $LAST is used. The different
types of instructions are
kil, for not killable instructions
decl, for declarations
del, for deletion
asg, for assignment
afx, for affix/unfix
cpy, for copy and merge
DEFAULT PARTS
POINTY provides many default parts in different instructions.
For the instructions of movement there is a part of the instruction that
can be left out. The system remembers the last movement instruction used
and supply the first part of it as default. That part is displayed on the
little box below the scalar box on the display.
Two global variables are used to store that default part (OLDCMD and OLDOBJ).
default part part of the instruction to be typed in
____________________________________________________________________________________
OLDCMD OLDOBJ
____________________________________________________________________________________
MOVE <frame_id> BY <vector>
TO <frame_id> {+<vector> {WRT <frame_id>}}
MOVEX {<frame_id>} BY <scalar>
MOVEY {<frame_id>} BY <scalar>
MOVEZ {<frame_id>} BY <scalar>
OPEN <hand> TO <scalar>
BY <scalar>
CLOSE <hand> TO <scalar>
BY <scalar>
DRIVE BJT(<number>) TO <scalar>
BY <scalar>
Other instructions allow a default part
instruction default
___________________________________________________________________________________
BARM← INPUT BARM (to update arm position)
CENTER BARM
CLOSE current file
<id>←INPUT POINTER
YARM← INPUT YARM (to update arm position)
OPEN TO|BY <scalar> BHAND
MOVEX BY <scalar> BARM
MOVEY BY <scalar> BARM
MOVEZ BY <scalar> BARM
READ DECLAR.AL
SAVE current file
WRITE current file FROM STATION
WRITE FROM <frame_id> current file
WRITE <file> FROM STATION
vector, rot.... *INCH, *INCHES, *DEG, *DEGREES (no dimension check)
HOW "CONSTRUCT" IS IMPLEMENTED
Three positions are required to define a reference system:
at the origin
on one main axis
on the plane between the previous axis and another main axis
So, given three vectors v1, v2 and v3, and knowing
v1 is at the origin of the frame
v2 is on the axis first_axis (f_axis)
v3 is on the plane through f_axis and second_axis (s_axis)
we want to determine the third_axis (t_axis).
We'll associate an integer number to each one of the main axes, to ease
the computations
xhat 1
yhat 2
zhat 3
These numbers relate the name of the axis to the number of the column in
the rotation matrix corresponding to it.
* the vector v1 gives the position of the new frame
(column 4 of the rotation matrix);
* the vector |v2-v1| gives the f_axis
(columm f_axis of the rotation matrix);
To determine the other two main axes (column s_axis and t_axis of the
rotation matrix) there are two different cases:
a) b)
↑ f_axis ↑ f_axis
v2 v2
v3 | | v3
| |
v1-----------→ t_axis v1------------→ s_axis
/ /
s_axis t_axis
/ /
t_axis = ||v2-v1|*|v3-v1|| t_axis = ||v3-v1|*|v2-v1||
s_axis = t_axis * f_axis s_axis = f_axis * t_axis
To determine what is the appropriate case it's enough to check if s_axis
follows f_axis in the regular order (case a) or not (case b). This check,
using the numbers associated to the axes, is a simple test on
permutations.
HOW TO HANDLE THE ROTATION MATRIX
POINTY uses a rotation matrix [1:5,1:4],
the part [1:3,1,3] is the rotation matrix
the part [1:3,4] is the translation part
the part [4,1:4] is used only to ease the operations
the part [5,1:3] contains the euler angles corresponding to the rot
the element [5,4] is >0 when the euler angles are valid
!!!!!!! WARNING the rotation matrix [1:3,1:3] used by POINTY is the transpose
of the rotation matrix used by the interface and by AL.
* how to compute the rotation matrix
The procedure XYZROT used to compute the rotation matrix, for a rotation
of an angle W about the axis V (with components CX, CY, CZ about the main
axes ) constructs the matrix with the following formulas
MATRIX ROT(3,3)$
ROT(1,1) := - COS(W)*CX**2 + COS(W) + CX**2$
ROT(1,2) := - COS(W)*CX*CY + CX*CY - CZ*SIN(W)$
ROT(1,3) := - COS(W)*CX*CZ + CX*CZ + CY*SIN(W)$
ROT(2,1) := - COS(W)*CX*CY + CX*CY + CZ*SIN(W)$
ROT(2,2) := - COS(W)*CY**2 + COS(W) + CY**2$
ROT(2,3) := - COS(W)*CY*CZ - CX*SIN(W) + CY*CZ$
ROT(3,1) := - COS(W)*CX*CZ + CX*CZ - CY*SIN(W)$
ROT(3,2) := - COS(W)*CY*CZ + CX*SIN(W) + CY*CZ$
ROT(3,3) := - COS(W)*CZ**2 + COS(W) + CZ**2$
(the previous rows are in a form readable by REDUCE 2)
The procedure SETROT is used to compute directly the rotation matrix
corresponding to ROT(ZHAT,TH)*ROT(YHAT,PH)*ROT(ZHAT,W) given the Euler
angles W, PH and TH (see next section).
* how to decode the rotation matrix
Usually the matrix is decoded computing the Euler angles.
To show how the decode process is done we'll show the symbolic product of
three rotations
ROT(ZHAT,TH)*ROT(YHAT,PH)*ROT(ZHAT,W)
(the interpretation of the product between rotations is the same as in AL)
given the three rotation matrices
MATRIX MATZTH(3,3); COMMENT ROT(ZHAT,TH);
MATZTH(1,1) := COS(TH);
MATZTH(1,2) := - SIN(TH);
MATZTH(1,3) := 0;
MATZTH(2,1) := SIN(TH);
MATZTH(2,2) := COS(TH);
MATZTH(2,3) := 0;
MATZTH(3,1) := 0;
MATZTH(3,2) := 0;
MATZTH(3,3) := 1;
MATRIX MATZPH(3,3); COMMENT ROT(YHAT,PH);
MATYPH(1,1) := COS(PH);
MATYPH(1,2) := 0;
MATYPH(1,3) := SIN(PH);
MATYPH(2,1) := 0;
MATYPH(2,2) := 1;
MATYPH(2,3) := 0;
MATYPH(3,1) := - SIN(PH);
MATYPH(3,2) := 0;
MATYPH(3,3) := COS(PH);
MATRIX MATZW(3,3); COMMENT ROT(ZHAT,W);
MATZW(1,1) := COS(W);
MATZW(1,2) := - SIN(W);
MATZW(1,3) := 0;
MATZW(2,1) := SIN(W);
MATZW(2,2) := COS(W);
MATZW(2,3) := 0;
MATZW(3,1) := 0;
MATZW(3,2) := 0;
MATZW(3,3) := 1;
we'll obtain the product
MATRIX EULER(3,3); COMMENT ROT(ZHAT,TH)*ROT(YHAT,PH)*ROT(ZHAT,W);
EULER(1,1) := COS(W)*COS(TH)*COS(PH) - SIN(W)*SIN(TH);
EULER(1,2) := - (COS(W)*SIN(TH) + SIN(W)*COS(TH)*COS(PH));
EULER(1,3) := COS(TH)*SIN(PH);
EULER(2,1) := COS(W)*SIN(TH)*COS(PH) + SIN(W)*COS(TH);
EULER(2,2) := COS(W)*COS(TH) - SIN(W)*SIN(TH)*COS(PH);
EULER(2,3) := SIN(TH)*SIN(PH);
EULER(3,1) := - COS(W)*SIN(PH);
EULER(3,2) := SIN(W)*SIN(PH);
EULER(3,3) := COS(PH);
The procedure EULERO extract from that matrix the angles W, PH, TH.
Sometimes we need to decode the rotation matrix in a different way. For
example to construct a matrix corresponding to the arm position, but with
the ZHAT pointing up vertically, we need to decode the matrix as a product
of rotations about the three main axes, and then to use only the component
of the rotation about ZHAT.
To show how the decode process is done we'll show the symbolic product of
three rotations
ROT(ZHAT,C)*ROT(YHAT,B)*ROT(ZHAT,A)
(the interpretation of the product between rotations is the same as in AL)
MATRIX MATX(3,3); COMMENT ROT(XHAT,A);
MATX(1,1) := 1;
MATX(1,2) := 0;
MATX(1,3) := 0;
MATX(2,1) := 0;
MATX(2,2) := COS(A);
MATX(2,3) := - SIN(A);
MATX(3,1) := 0;
MATX(3,2) := SIN(A);
MATX(3,3) := COS(A);
MATRIX MATY(3,3); COMMENT ROT(YHAT,B);
MATY(1,1) := COS(B);
MATY(1,2) := 0;
MATY(1,3) := SIN(B);
MATY(2,1) := 0;
MATY(2,2) := 1;
MATY(2,3) := 0;
MATY(3,1) := - SIN(B);
MATY(3,2) := 0;
MATY(3,3) := COS(B);
MATRIX MATZ(3,3); COMMENT ROT(ZHAT,C);
MATZ(1,1) := COS(C);
MATZ(1,2) := - SIN(C);
MATZ(1,3) := 0;
MATZ(2,1) := SIN(C);
MATZ(2,2) := COS(C);
MATZ(2,3) := 0;
MATZ(3,1) := 0;
MATZ(3,2) := 0;
MATZ(3,3) := 1;
we'll obtain the product
MATRIX MATPROD(3,3); COMMENT ROT(ZHAT,C)*ROT(YHAT,B)*ROT(XHAT,A);
MATPROD(1,1) := COS(C)*COS(B);
MATPROD(1,2) := SIN(A)*COS(C)*SIN(B) - SIN(C)*COS(A);
MATPROD(1,3) := SIN(A)*SIN(C) + COS(C)*SIN(B)*COS(A);
MATPROD(2,1) := SIN(C)*COS(B);
MATPROD(2,2) := SIN(A)*SIN(C)*SIN(B) + COS(C)*COS(A);
MATPROD(2,3) := - SIN(A)*COS(C) + SIN(C)*SIN(B)*COS(A);
MATPROD(3,1) := - SIN(B);
MATPROD(3,2) := SIN(A)*COS(B);
MATPROD(3,3) := COS(B)*COS(A);
The procedure DECODE decodes the matrix computing the three angles A, B
and C. When the angle B is 90 degrees it's impossible to compute A and C,
but it's only possible to compute their difference. The procedure DECODE
forces A to 0 and returns in C the value of (C-A).
THE EXPRESSION EVALUATOR
The expression evaluator is a top down single stage evaluator.
It tries to perform computations as soon as something is in a stage
that can be evaluated. No explicit tree of the parsed expression
is built up - an implicit tree is formed by means of the three recursive
routines that evaluate expressions, terms and factors.
The syntax of the three are as follows:
expressions E: <+ T | - T | T > {+T|-T}
term T: F { * F | / F }
factor F: ( E , E, E,... ) or | E |
or func(E,...)
or E WRT E
or E REL E
The expression evaluator (invoked by GTEXPR)
returns a record pointer to a record
of class TREE which have fields DATA and DTYPE.
DATA is a record pointer field of class SCALAR,VECTOR,TRANS,ROT or FRAME
DTYPE is an integer which indicates which record class DATA corresponds to.
The expression evaluator calls the following procedures:
GTOKEN which returns the next symbol and its type
OPSCAL,OPVET,etc which perform the actual arithmetic
ERROR which is defined by POINTY and is the routine for
handling error messages. Since ERROR does not return
control to the expression evaluator, continuation
of computation is started afresh with the corrected
expression.
APRIL 21, 1978.
The expression evaluator has been changed to complete the process in two
passes. At the first pass, the expression tree is built up. It is then
evaluated on a second pass. The implementation was changed to allow the
use of the same expression evaluator to build up the internal form of a
function expression. Functions can now been evaluated.
The problem of dummy variables and global variables that
are deleted have been addressed. The dummy parameter of a function
must be an undeclared identifier, but those names can be used later on.
When the function definition is edited, there will be no confusion between
the old parameters and new variables of the same name.
The use of global variables in function definitions presents
the problem of ensuring that the function is no longer valid when
the global variable is deleted. This is done by maintaining pointers
in the symbol record that keep track of which functions/variables
make use /are used by which.
Thus when a global variable is deleted, POINTY will inform the user
of its effect, and prevent evaluation of functions using that
variable, until the user redefines that variable again.
[msm]
SOURCE FILE PROTOCOL
To keep track of the different files and the procedures in them,
a new protocol has been set up. Each file to be compiled into a load
module must have an id associated with it, and must call an auxiliary
header file HEADER.SAI[PNT,HE] of internal/external declarations.
HEADER.SAI[PNT,HE] has the following properties:
It has a version number associated with it that it gives to
each of the files that are compiled using it. The version number should
be changed each time any changes are made in HEADER.SAI that affect
more than one of the other files.
HEADER.SAI is responsible for all macro definitions, abbreviations,
and conditional compilation flags not otherwise defined. It declares
all variables either internal or external depending on the flag
associated with it. Procedures are declared forward internal or
external so that SAIL can check for errors made in the type or
nature of the procedures and the arguments associated with it.
Internal declarations only of procedures can exist in source files.
ALL other internal and external declarations MUST be made in the
HEADER.SAI.
HEADER.SAI is also responsible for calling all the other
source files and loadmodules necessary for a particular compiled
module. This is to ensure that all source_file and load_module
requirements are kept together in one place, and hopefully to make it
easier to trace the absence of missing files during loading and to
tell where the reference to it is located.
DOCUMENTATION OF THE DEBUGGING FACILITIES IN POINTY
--------------------------------------------------------------------------
To set POINTY in debug mode the instruction
SETSTATUS(DEBUG) or
DEBUGON
are required. You can reset POINTY to the normal mode by typing
RESETSTATUS(DEBUG) or
DEBUGOFF
When in debug mode POINTY will stop at the beginning of any compound
statement you type in, while it doesn't stop if you type in a simple
statement.
When in debug mode POINTY reads general POINTY expressions typed by the
user, evaluates them in the context of the place in the program where
execution was suspended. The evaluation is performed just as if the user
had inserted an extra statement into the original program at the point
where execution was suspended. The user may ask to evaluate any POINTY
expression whose evaluation would be legal at the point at which the
execution of the program was suspended.
POINTY prompts the user for input by typing a ":*:". Input can be edited
using the standard line editor. The activation character is the semicolon
or the carriage return, whathever comes first.
The POINTY instructions typed are numbered starting from 1, so that
reference to an instruction can be done through its number, or
"coordinate".
--------------------------------------------------------------------------
Here is the list of instructions available ONLY in debug mode:
--------------------------------------------------------------------------
BREAK(COORD)
BREAK("PROCEDURE_NAME", COORD)
Put a breakpoint at the specified point.
HALT
Send the control to the 10.
QUIT
Quit the program under execution. Can be called only when outside from
procedures.
RESTART
Restart the program from the beginning. Can be called only when outside
from procedures.
TEXT
TEXT(MIN#)
TEXT(MIN#,MAX#)
TEXT("PROCEDURE_NAME",MIN#)
TEXT("PROCEDURE_NAME",MIN#,MAX#)
Show the source text, from MIN# to MAX#. If MAX# < MIN# set MAX# to be
MIN#+MAX#. If MAX# is omitted set it to be MIN#. If both numbers are
omitted show the next instruction to be executed.
TRAPS
Show the exixting breakpoints.
UNBREAK(COORD)
UNBREAK("PROCEDURE_NAME", COORD)
Remove a breakpoint from the specified point. Complain if no breakpoint
has been set.
!!GO, <CONTROL>G
Continue the execution, from the point where it was suspended until a
breakpoint or the end of the execution is reached.
!!STEP, <CONTROL>S
Execute next statement and stop after that, doing single stepping into
procedures or compound statements.
!!GSTEP, <CONTROL>X
Execute next statement, considering compound statements or procedure calls
as a single statement, and stops after that.
--------------------------------------------------------------------------
KNOWN BUGS
--------------------------------------------------------------------------
TRAPS shows the breakpoints in the main program and in untyped procedures
(doesn't work yet for typed procedures)
COBEGIN/COEND cause severe problems on the 11. Don't try it!
--------------------------------------------------------------------------
IMPLEMENTATION NOTES
--------------------------------------------------------------------------
POINTY keeps the information associated with the program being debugged in
a record, associated with the pcode corresponding to the statement itself.
There is one field in the record EXPR$, called DBEXPR, pointing to a
record of type DBEXPR.
Each time PARSE is called the position in the symbolic text is saved in a
local variable, and a global counter of instructions is increased by one.
The procedure $AAPPEND takes care of appending the DBEXPR record of the
different expressions being appended.
When the parsing of the statement is done the procedure MARK is called, to
mark the beginning and the end of the pcode so far constructed. The marks
set are made up by two words: one indicating that is the beginning of an
instruction (bit 14 set to 1) and the offset, the second one the
coordinate number. Same thing at the end, except the mark is in bit 13.
Before executing the pcode another procedure, DBINIT, is called, to
complete the initializations in DBEXPR. If the program is only a simple
statement it is directly executed, while if it's a compound statement the
appropriate pcode to return the control to the 10 before executing it, is
produced and attached in front of the pcode.
The interpreter on the 11 has been sligthly modified to be able to detect
the initial marks of statements. According to the debugstatus (go, single
stepping, .....) different actions are taken and eventually the control is
sent to the 10, together with the offset and the coordinate number of the
corresponding statement. While in debug mode a new area in the pcode
buffer is set, where the new pcode eventually generated during the
debugging is put, so that it will not overlap with the pcode being
debugged. When the user is done and wants to proceed the debugstatus is
modified and then the execution on the 11 resumed starting at the point
where it was suspendended.
The record DBEXPR has the following fields:
#COORD = max number of coordinate in the POINTY program
BODY = string with the symbolic text of the program
COORD = array [1:#coord] containing
(36 bits) 000000000000000000000 00000000000000 0
coordinate of offset trap
the instruction (≠0 if procedure) (>0 no breakpoint, =1 breakpoint)
TXTPOS = array [1:#coord] containing
000000000000000000 000000000000000000
position in the how long is the instruction
text where the (number of characters)
instruction starts
PCDPOS = array [1:#coord] containing
000000000000000000 000000000000000000
position in the how long is the pcode
pcode where the (number of words)
pcode starts
BLOCK = array [1:#coord] containing
000000000000000000000000000000000000
pointer to the block
whom the instruction belongs to
There are some global variables used:
!DEBUG is true when the system is in debugmode (after having done DEBUGON)
!!DEBUGGING is true when the system is actually debugging
$$DEBUG is the pointer to the DBEXPR record of the current expression
NEWPCDBUF is the start of the pcode buffer for pcode generated/interpreted
while debugging;
$COORD is the coordinate returned by the 11 of the next instruction to
be executed
$OFFSET is the offset of the next instruction to be executed
$WHERE is the rptr to the procedure whose offset is in $OFFSET
The marks at the beginning and at the end of the instructions are
#BMARK= '240000
#EMARK= '220000
They are greater than any pcode generated by the system, so that they can
be easily recognized during the construction of the array PCDPOS (in
DBINIT)
When the system is in DEBUGLOOP any instruction can be typed in. Some
instructions have a special effect because they determine the next
instruction to be executed.
RESTART deletes all the local variables and restarts the program
QUIT deletes the local variables and terminate the execution of
the program
αS, αX, αG control the execution as indicated before.
IMPLEMENTATION
--------------
POINTY keeps the information associated with the program being debugged in
a record, associated with the pcode corresponding to the statement itself.
There is one field in the record EXPR$, called DBEXPR, pointing to a
record of type DBEXPR.
Each time PARSE is called the position in the symbolic text is saved in a
local variable, and a global counter of instructions is increased by one.
The procedure $AAPPEND takes care of appending the DBEXPR record of the
different expressions being appended.
When the parsing of the statement is done the procedure MARK is called, to
mark the beginning and the end of the pcode so far constructed. The marks
set are made up by two words: one indicating that is the beginning of an
instruction (bit 14 set to 1) and the offset, the second one the
coordinate number. Same thing at the end, except the mark is in bit 13.
Before executing the pcode another procedure, DBINIT, is called, to
complete the initializations in DBEXPR. If the program is only a simple
statement it is directly executed, while if it's a compound statement the
appropriate pcode to return the control to the 10 before executing it, is
produced and attached in front of the pcode.
The interpreter on the 11 has been sligthly modified to be able to detect
the initial marks of statements. According to the debugstatus (go, single
stepping, .....) different actions are taken and eventually the control is
sent to the 10, together with the offset and the coordinate number of the
corresponding statement. While in debug mode a new area in the pcode
buffer is set, where the new pcode eventually generated during the
debugging is put, so that it will not overlap with the pcode being
debugged. When the user is done and wants to proceed the debugstatus is
modified and then the execution on the 11 resumed starting at the point
where it was suspendended.
The record DBEXPR has the following fields:
#COORD = max number of coordinate in the POINTY program
BODY = string with the symbolic text of the program
COORD = array [1:#coord] containing
(36 bits) 000000000000000000000 00000000000000 0
coordinate of offset trap
the instruction (≠0 if procedure) (>0 no breakpoint, =1 breakpoint)
TXTPOS = array [1:#coord] containing
000000000000000000 000000000000000000
position in the how long is the instruction
text where the (number of characters)
instruction starts
PCDPOS = array [1:#coord] containing
000000000000000000 000000000000000000
position in the how long is the pcode
pcode where the (number of words)
pcode starts
BLOCK = array [1:#coord] containing
000000000000000000000000000000000000
pointer to the block
whom the instruction belongs to
There are some global variables used:
!DEBUG is true when the system is in debugmode (after having done DEBUGON)
!!DEBUGGING is true when the system is actually debugging
$$DEBUG is the pointer to the DBEXPR record of the current expression
NEWPCDBUF is the start of the pcode buffer for pcode generated/interpreted
while debugging;
$COORD is the coordinate returned by the 11 of the next instruction to
be executed
$OFFSET is the offset of the next instruction to be executed
$WHERE is the rptr to the procedure whose offset is in $OFFSET
The marks at the beginning and at the end of the instructions are
#BMARK= '240000
#EMARK= '220000
They are greater than any pcode generated by the system, so that they can
be easily recognized during the construction of the array PCDPOS (in
DBINIT)
When the system is in DEBUGLOOP any instruction can be typed in. Some
instructions have a special effect because they determine the next
instruction to be executed.
RESTART deletes all the local variables and restarts the program
QUIT deletes the local variables and terminate the execution of
the program
αS, αX, αG control the execution as indicated before.
POINTY RUNTIME
--------------
POINTY.PAL
AL.PAL[PNT,HE]
ALHEAD.PAL[AL,HE]
K1DEF.PAL[11,SYS]
ALIO2.PAL[PNT,HE]
LARGEB.PAL[AL,HE]
SMALLB.PAL[AL,HE]
INTERP.PAL[PNT,HE]
INTOPS.PAL[AL,HE]
PINTRP.PAL[PNT,HE]
ALDISP.PAL[PNT,HE]
TALK10.PAL[PNT,HE]
FLOAT.PAL[AL,HE]
GRAPHS.PAL[AL,HE]
PNTARM.PAL
ALARM.PAL[PNT,HE]
ARM.PAL[AL,HE]
EULER.PAL[AL,HE]
PARM.PAL[PNT,HE]
K1[11,SYS]
PNTY[PNT,HE]